package com.yunyike.service.impl;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.UUID;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.yunyike.constants.CommonConstant;
import com.yunyike.constants.CouponConstants;
import com.yunyike.constants.OrderConstants;
import com.yunyike.constants.StockConstants;
import com.yunyike.dto.UserOrdersDTO;
import com.yunyike.dto.cart.CartMerchandise;
import com.yunyike.dto.cart.CartPromotionGroup;
import com.yunyike.dto.cart.CartShopGroup;
import com.yunyike.exception.BusinessException;
import com.yunyike.mapper.OrdersMapper;
import com.yunyike.model.Coupon;
import com.yunyike.model.Merchandise;
import com.yunyike.model.OrderCouponMapping;
import com.yunyike.model.OrderMerchandiseMapping;
import com.yunyike.model.OrderRecepientMapping;
import com.yunyike.model.OrderTimeline;
import com.yunyike.model.Orders;
import com.yunyike.model.Recepient;
import com.yunyike.model.Stock;
import com.yunyike.model.StockWater;
import com.yunyike.model.User;
import com.yunyike.service.ICartService;
import com.yunyike.service.ICouponService;
import com.yunyike.service.IMerchandiseService;
import com.yunyike.service.IOrderCouponMappingService;
import com.yunyike.service.IOrderMerchandiseMappingService;
import com.yunyike.service.IOrderRecepientMappingService;
import com.yunyike.service.IOrderService;
import com.yunyike.service.IOrderTimelineService;
import com.yunyike.service.IStockService;
import com.yunyike.service.IStockWaterService;
import com.yunyike.utils.PKUtils;

/**
 * @author zhengqiang.shi
 * 2015年11月26日 下午10:17:59
 */
@Service("orderServiceImpl")
@Transactional
public class OrderServiceImpl implements IOrderService {

	private static Logger log = LoggerFactory.getLogger(OrderServiceImpl.class);

	@Autowired
	private OrdersMapper ordersMapper;
	
	@Autowired
	private IOrderCouponMappingService orderCouponMappingService;
	
	@Autowired
	private IOrderMerchandiseMappingService orderMerchandiseMappingService;
	
	@Autowired
	private IOrderRecepientMappingService orderRecepientMappingService;
	
	@Autowired
	private IMerchandiseService merchandiseService;
	
	@Autowired
	private IStockService stockService;
	
	@Autowired
	private IStockWaterService stockWaterService;
	
	@Autowired
	private IOrderTimelineService orderTimelineService;
	
	@Autowired
	private ICartService cartService;
	
	@Autowired
	private ICouponService couponService;
	
	public Orders doSubmit(User user,Recepient recepient, Coupon coupon, com.yunyike.dto.cart.CartDTO cartDTO){
		
		Orders saveOrder = null;
		try {
			// 保存订单
			saveOrder = saveOrder(user,cartDTO);
			if(saveOrder == null){
				throw new BusinessException("saveOrder has error");
			}
			
			// 保存订单使用的收货信息
			saveOrderRecepientMapping(saveOrder.getOrderId(), recepient);
			
			// 保存订单使用的优惠券
			saveOrderCouponMapping(saveOrder.getOrderId(), coupon);
			
			// 保存订单购买的商品
			saveOrderMerchandiseMapping(saveOrder.getOrderId(), cartDTO);
			
			// 预扣库存
			setStock(cartDTO);
			
			// 订单流水
			setOrderTimeLine(saveOrder.getOrderId(),CommonConstant.NUMBER_0);
			
			// 删除购物车
			removeCart(user, cartDTO);
			
		} catch (Exception e) {
			throw new BusinessException("doSubmit has error,message:"+e.getMessage(),e);
		}
		
		return saveOrder;
	}
	
	private void removeCart(User user, com.yunyike.dto.cart.CartDTO cartDTO){
		List<String> merchandiseIds = new ArrayList<String>();
		List<CartShopGroup> cartShopGroups = cartDTO.getCartShopGroups();
		for (CartShopGroup cartShopGroup : cartShopGroups) {
			
			List<CartPromotionGroup> cartPromotionGroups = cartShopGroup.getCartPromotionGroups();
			for (CartPromotionGroup cartPromotionGroup : cartPromotionGroups) {
				
				List<CartMerchandise> cartMerchandises = cartPromotionGroup.getCartMerchandises();
				for (CartMerchandise cartMerchandise : cartMerchandises) {
					String merchandiseId = cartMerchandise.getMerchandiseId();
					merchandiseIds.add(merchandiseId);
				}
			}
		}
		
		int removeCart = cartService.removeCart(user, merchandiseIds);
		if(removeCart != CommonConstant.NUMBER_1){
			throw new BusinessException("cartService.removeCart failed.");
		}
	}
	
	private void setOrderTimeLine(String orderId,Integer orderStatus){
		
		OrderTimeline orderTimeline = new OrderTimeline();
		orderTimeline.setOrderId(orderId);
		orderTimeline.setOrderStatus(orderStatus);
		orderTimeline.setOrderTimelineId(UUID.randomUUID().toString());
		orderTimeline.setCtime(new Date());
		
		orderTimelineService.insertOrderTimeline(orderTimeline);
	}
	
	private void setStock(com.yunyike.dto.cart.CartDTO cartDTO){
		
		List<String> merchandiseIds = new ArrayList<String>();
		Map<String, CartMerchandise> cartMerchandiseMap = new HashMap<String, CartMerchandise>();
		List<CartShopGroup> cartShopGroups = cartDTO.getCartShopGroups();
		for (CartShopGroup cartShopGroup : cartShopGroups) {
			
			List<CartPromotionGroup> cartPromotionGroups = cartShopGroup.getCartPromotionGroups();
			for (CartPromotionGroup cartPromotionGroup : cartPromotionGroups) {
				
				List<CartMerchandise> cartMerchandises = cartPromotionGroup.getCartMerchandises();
				for (CartMerchandise cartMerchandise : cartMerchandises) {
					String merchandiseId = cartMerchandise.getMerchandiseId();
					cartMerchandiseMap.put(merchandiseId, cartMerchandise);
					merchandiseIds.add(merchandiseId);
				}
			}
		}
		Map<String, Stock> stockMap = stockService.getStock(merchandiseIds);
		Iterator<Entry<String, Stock>> iterator = stockMap.entrySet().iterator();
		
		while(iterator.hasNext()){
			Entry<String, Stock> next = iterator.next();
			String merchandiseId = next.getKey();
			Stock stock = next.getValue();
			stock.setStockPreSubQty(stock.getStockPreSubQty()+cartMerchandiseMap.get(merchandiseId).getMerchandiseQty());
			
			int updateStock = stockService.updateStock(stock);
			if(updateStock != CommonConstant.NUMBER_1){
				throw new BusinessException("pre sub stock qty failed.");
			}
			
			StockWater stockWater = new StockWater();
			stockWater.setStockWaterId(UUID.randomUUID().toString());
			stockWater.setStockWaterMerchandiseId(merchandiseId);
			stockWater.setStockWaterQty(cartMerchandiseMap.get(merchandiseId).getMerchandiseQty());
			stockWater.setStockWaterType(StockConstants.STOCK_TYPE_3);
			stockWater.setCtime(new Date());
			
			int insertStockWater = stockWaterService.insertStockWater(stockWater);
			if(insertStockWater != CommonConstant.NUMBER_1){
				throw new BusinessException("insert stock water failed.");
			}
		}
	}
	
	private void saveOrderRecepientMapping(String orderId, Recepient recepient) {
		
		OrderRecepientMapping orm = new OrderRecepientMapping();
		orm.setOrderId(orderId);
		orm.setIsDefault(recepient.getIsDefault());
		orm.setRecepientAddress(recepient.getRecepientAddress());
		orm.setRecepientAreaId(recepient.getRecepientAreaId());
		orm.setRecepientAreaName(recepient.getRecepientAreaName());
		orm.setRecepientCityId(recepient.getRecepientCityId());
		orm.setRecepientCityName(recepient.getRecepientCityName());
		orm.setRecepientEmail(recepient.getRecepientEmail());
		orm.setRecepientId(recepient.getRecepientId());
//		orm.setRecepientIdCard(recepient.getRecepientIdCard());
//		orm.setRecepientIdCard(idCard.getIdentityCardNumber());
		orm.setRecepientIdCardPhoto(recepient.getRecepientIdCardPhoto());
		orm.setRecepientName(recepient.getRecepientName());
		orm.setRecepientPostCode(recepient.getRecepientPostCode());
		orm.setRecepientProvinceId(recepient.getRecepientProvinceId());
		orm.setRecepientProvinceName(recepient.getRecepientProvinceName());
		orm.setRecepientStatus(recepient.getRecepientStatus());
		orm.setRecepientTel(recepient.getRecepientTel());
		orm.setUserId(recepient.getUserId());
		
		int insert = orderRecepientMappingService.insert(orm);
		
		if(insert != CommonConstant.NUMBER_1){
			log.info("submit order save order recepient failed.result is:"+insert);
			throw new BusinessException();
		}
		
	}

	public void saveOrderMerchandiseMapping(String saveOrder, com.yunyike.dto.cart.CartDTO cartDTO){
		
		List<String> merchandiseIds = new ArrayList<String>();
		Map<String, CartMerchandise> cartMerchandiseMap = new HashMap<String, CartMerchandise>();
		List<CartShopGroup> cartShopGroups = cartDTO.getCartShopGroups();
		for (CartShopGroup cartShopGroup : cartShopGroups) {
			
			List<CartPromotionGroup> cartPromotionGroups = cartShopGroup.getCartPromotionGroups();
			for (CartPromotionGroup cartPromotionGroup : cartPromotionGroups) {
				List<CartMerchandise> cartMerchandises = cartPromotionGroup.getCartMerchandises();
				
				for (CartMerchandise cartMerchandise : cartMerchandises) {
					String merchandiseId = cartMerchandise.getMerchandiseId();
					merchandiseIds.add(merchandiseId);
					cartMerchandiseMap.put(merchandiseId, cartMerchandise);
				}
			}
		}
		
		List<Merchandise> list = merchandiseService.findMerchandiseByIds(merchandiseIds);
		
		for (Merchandise merchandise : list) {
			
			OrderMerchandiseMapping omm = new OrderMerchandiseMapping();
			omm.setOrderId(saveOrder);
			omm.setCtime(merchandise.getCtime());
			omm.setMerchandiseBarcode(merchandise.getMerchandiseBarcode());
			omm.setMerchandiseCurrency(merchandise.getMerchandiseCurrency());
			omm.setMerchandiseDesc(merchandise.getMerchandiseDesc());
			omm.setMerchandiseDomesticPrice(merchandise.getMerchandiseDomesticPrice());
			omm.setMerchandiseIcon(merchandise.getMerchandiseIcon());
			omm.setMerchandiseId(merchandise.getMerchandiseId());
			omm.setMerchandiseNameCn(merchandise.getMerchandiseNameCn());
			omm.setMerchandiseNameEn(merchandise.getMerchandiseNameEn());
			omm.setMerchandiseNumber(merchandise.getMerchandiseNumber());
			omm.setMerchandisePrice(merchandise.getMerchandisePrice());
			omm.setMerchandiseQrcode(merchandise.getMerchandiseQrcode());
			omm.setMerchandiseSpec(merchandise.getMerchandiseSpec());
			omm.setMerchandiseVolume(merchandise.getMerchandiseVolume());
			omm.setMerchandiseWeight(merchandise.getMerchandiseWeight());
			omm.setShopId(merchandise.getShopId());
			omm.setMerchandiseQty(cartMerchandiseMap.get(merchandise.getMerchandiseId()).getMerchandiseQty());
			int insert = 0;
			try {
				insert = orderMerchandiseMappingService.insert(omm);
			} catch (Exception e) {
				throw new BusinessException("orderMerchandiseMappingService.insert has error.message:"+e.getMessage(),e);
			} finally {
				if(insert == 0){
					throw new BusinessException("orderMerchandiseMappingService.insert return 0,return false.");
				}
			}
			
		}
	}
	
	public void saveOrderCouponMapping(String saveOrder, Coupon coupon){
		
		if(coupon == null){
			return;
		}
		
		OrderCouponMapping ocm = new OrderCouponMapping();
		ocm.setOrderCouponMappingId(UUID.randomUUID().toString());
		ocm.setOrderId(saveOrder);
		ocm.setCouponId(coupon.getCouponId());
		log.info("start orderCouponMappingService.insert ,ocm:{}",ocm);
		int insert = 0;
		int updateCoupon = 0;
		try {
			// 插入订单优惠券对应表
			insert = orderCouponMappingService.insert(ocm);
			
			// 更新优惠券状态
			Coupon c = new Coupon();
			c.setCouponId(coupon.getCouponId());
			c.setCouponStatus(CouponConstants.COUPON_STATUS_1);
			updateCoupon = couponService.updateCoupon(c);
		} catch (Exception e) {
			log.error("orderCouponMappingService.insert has error.message:"+e.getMessage(),e);
			throw new BusinessException();
		} finally {
			if(insert == 0 || updateCoupon == 0){
				log.error("orderCouponMappingService.insert or updateCoupon return 0");
				throw new BusinessException();
			}
		}
	}
	
	public Orders saveOrder(User user,com.yunyike.dto.cart.CartDTO cartDTO){
		
		String orderId = UUID.randomUUID().toString();
		
		Orders orders = new Orders();
		orders.setOrderPrice(cartDTO.getTotalPrice().doubleValue());
		orders.setOrderDiscountPrice(cartDTO.getDiscountPrice().doubleValue());
		orders.setOrderFreightPrice(cartDTO.getFreightPrice().doubleValue());
		orders.setOrderId(orderId);
		orders.setOrderNumber(PKUtils.getPrimaryKey());
		orders.setUserId(user.getUserId());
		orders.setOrderStatus(OrderConstants.ORDER_STATUS_0);
		orders.setOrderDateTime(new Date());
		
		int result = 0;
		try {
			result = ordersMapper.insertSelective(orders);
		} catch (Exception e) {
			log.error("orderMapper.insertSelective has error.message:"+e.getMessage(),e);
			throw new BusinessException();
		} finally {
			if(result == 0){
				log.error("orderMapper.insertSelective result is 0");
				throw new BusinessException();
			}
		}
		
		Orders curOrders;
		try {
			curOrders = ordersMapper.selectByPrimaryKey(orderId);
		} catch (Exception e) {
			throw new BusinessException("ordersMapper.selectByPrimaryKey has error.message:"+e.getMessage(),e);
		}
		
		return curOrders;
	}
	
	public Map<String, Integer> findOrderCountByCondition(User user) {
		
		// 初始化返回参数
		Map<String, Integer> ordersMap = new HashMap<String, Integer>();
		ordersMap.put("4", 0);//待支付
		ordersMap.put("3", 0);//已收货
		ordersMap.put("2", 0);//待收货
		try {
			UserOrdersDTO dto = new UserOrdersDTO();
			dto.setUserId(user.getUserId());
			List<Map> orderCounts = ordersMapper.findUserOrdersCount(dto);
			for(Map map :orderCounts){
				ordersMap.put(map.get("order_status")+"",Integer.parseInt(map.get("status_count")+""));
			}
		} catch (Exception e) {
			log.error("ordersMapper.findUserOrders has error.message:"+e.getMessage(),e);
			return ordersMap;
		}
		return ordersMap;
	}
	
	/**
	 * 根据状态获取用户的订单信息（待支付、已收货、未收货）
	 */
	public List<UserOrdersDTO> findUserOrders(UserOrdersDTO param){
		List<UserOrdersDTO>  resultList = ordersMapper.findUserOrders(param);
		if(resultList!=null&&resultList.size()>0){
			for(UserOrdersDTO dto:resultList){
				dto.setOldFreightPrice(dto.getOrderFreightPrice().add(dto.getOrderFreightDiscountPrice()));
				dto.setOldOrderPrice(dto.getOrderPrice().subtract(dto.getOrderFreightPrice()));
			}
		}
		return resultList;
	}
	
	public String updateOrderStatu(UserOrdersDTO dto,Integer orderStatus) {
		Orders order= ordersMapper.selectByPrimaryKey(dto.getOrderId());
		if(order==null){
			return "订单不存在";
		}else if(!dto.getUserId().equals(order.getUserId())){
			return "您没有权限操作该订单";
		}else{
			Orders upOrder= new Orders();
			upOrder.setOrderStatus(orderStatus);
			upOrder.setOrderId(order.getOrderId());
			int result = ordersMapper.updateByPrimaryKeySelective(upOrder);
			if(result==0)return "发生异常，操作失败";
		}
		return null;
	}

	public Orders selectByPrimaryKey(String orderId) {
		return ordersMapper.selectByPrimaryKey(orderId);
	}

	/**
	 * 提交订单
	 */
	public Orders submitOrder(User user, Recepient recepient, Coupon coupon, com.yunyike.dto.cart.CartDTO cartDTO) {
		
		// 设置优惠券价格
		setCouponPrice(coupon, cartDTO);
		
		// 保存订单
		Orders orders = null;
		try {
			orders = doSubmit(user, recepient, coupon, cartDTO);
		} catch (BusinessException e) {
			throw new BusinessException("submitOrder failed."+e.getMessage(),e);
		} 
		
		if(orders == null){
			throw new BusinessException("doSubmit is null.service save order failed.saveOrder has error.");
		}
		
		return orders;
	}
	
	private void setCouponPrice(Coupon coupon, com.yunyike.dto.cart.CartDTO cartDTO){
		
		if(coupon == null){
			return;
		}
		
		BigDecimal totalMerchandisePrice = cartDTO.getTotalMerchandisePrice();
		BigDecimal discountPrice = cartDTO.getDiscountPrice();
		
		Double couponAmount = coupon.getCouponAmount();
		
		totalMerchandisePrice = totalMerchandisePrice.subtract(new BigDecimal(couponAmount));
		
		if(totalMerchandisePrice.compareTo(new BigDecimal(CommonConstant.NUMBER_0)) == -1){
			totalMerchandisePrice = new BigDecimal(CommonConstant.NUMBER_0);
			discountPrice = discountPrice.add(new BigDecimal(couponAmount).subtract(totalMerchandisePrice));
		}else{
			discountPrice = discountPrice.add(new BigDecimal(couponAmount));
		}
		
		cartDTO.setTotalMerchandisePrice(totalMerchandisePrice);
		cartDTO.setDiscountPrice(discountPrice);
	}
}
